package com.bsj.power.pls.netty;

import com.bsj.power.common.netty.CT60_constant;
import lombok.extern.slf4j.Slf4j;

import java.util.zip.CRC32;

/**
 * @Description 指令下发工具类
 * @Author zhaoyang
 * @Date 2024/9/23 15:27
 */
@Slf4j
public class CTInstructUtils {
    // 默认密钥
    public static final String secretKey = "TP@CT60";
    private static final String begin = "{";
    private static final String end = "}";
    private static final String split_comma = ",";

    // 设备订阅主题，根据deviceId组装
    private static final String topic_send_front = "/cnpower/";
    private static final String topic_send_back = "/user/get";


    /**
     * 报文序列号
     */
    private static int msgSn = 0;

    /**
     * 组装设备登入报文回复
     *
     * @param deviceId
     * @return
     */
    public static byte[] assembleLoginReply(String deviceId) {
        // "PM:1;" 默认直接给成功
        String beforeCheckStr = CT60_constant.CN + split_comma + deviceId + split_comma + "PM:1;" + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        return cmd.getBytes();

    }


    /**
     * 组装工牌弹出指令
     *
     * @param deviceId
     * @param stockSerialNum
     * @return
     */
    public static byte[] assembleUwbPopCmd(String deviceId, Integer stockSerialNum) {
        String beforeCheckStr = CT60_constant.CP + split_comma + getMsgSn() + split_comma + deviceId + split_comma + stockSerialNum + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        return cmd.getBytes();

    }

    /**
     * 组装工牌弹出指令
     *
     * @param deviceId
     * @param stockSerialNum
     * @return
     */
    public static String assembleUwbPopCmdStr(String deviceId, Integer stockSerialNum) {
        String beforeCheckStr = CT60_constant.CP + split_comma + getMsgSn() + split_comma + deviceId + split_comma + stockSerialNum + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        return cmd;

    }


    /**
     * 组装设备状态查询指令 设备默认三分钟上报一次状态，但是三分钟内设备有动作的话，会进行延迟，避免同步问题，服务端要视情况进行主动查询
     *
     * @param deviceId 卡机设备 ID
     * @param cmdType  命令参数:0 表示查询全部仓位信息；1~60 表示单独查询对应仓位的信息
     * @return
     */
    public static byte[] assembleDevStateQueryCmd(String deviceId, Integer cmdType) {
        String beforeCheckStr = CT60_constant.CQ + split_comma + getMsgSn() + split_comma + deviceId + split_comma + cmdType + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        return cmd.getBytes();

    }

    /**
     * 组装工牌归还上报回复指令
     *
     * @param deviceId  卡机设备 ID
     * @param serialNum 命令参数:0 表示查询全部仓位信息；1~60 表示单独查询对应仓位的信息
     * @param state     确认码：1 表示确认正常 2 表示确认异常，不弹出 3 表示确认异常，需要弹出
     * @return
     */
    public static byte[] assembleStockReturnReply(String deviceId, Integer serialNum, Integer state) {
        String beforeCheckStr = CT60_constant.CR + split_comma + getMsgSn() + split_comma + deviceId + split_comma
                + serialNum + split_comma + state + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        log.info("准备回复工牌归还上报命令：msg={}", cmd);

        return cmd.getBytes();

    }


    /**
     * 组装仓位禁用或启用控制指令
     *
     * @param deviceId  卡机设备 ID
     * @param serialNum 仓位号：范围 1~60。
     * @param state     控制参数：1 表示禁用该仓位，0 表示启用该餐位
     * @return
     */
    public static byte[] assembleStockDisableOrEnableCmd(String deviceId, Integer serialNum, Integer state) {
        String beforeCheckStr = CT60_constant.CL + split_comma + getMsgSn() + split_comma + deviceId + split_comma
                + serialNum + split_comma + state + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        return cmd.getBytes();

    }


    /**
     * 组装升级命令
     *
     * @param opCode     操作码
     * @param httpHost   http下载的ip
     * @param httpPort   http下载的port
     * @param filename   文件名
     * @param MD5        md5
     * @param fileLength 文件长度
     * @return
     */
    public static byte[] assembleFileUpgradeCmd(Integer opCode, String httpHost, Integer httpPort, String filename, String MD5, Integer fileLength) {
        // String cmdStr = "{OT,1,47.113.121.87,9992,TP_CT60_ETH_V1.240930.1,CB8210D319D39A1280010802CC6C7B3B,49700,1B36}";
        String beforeCheckStr = CT60_constant.OT + split_comma + opCode + split_comma + httpHost + split_comma + httpPort + split_comma
                + filename + split_comma + MD5 + split_comma + fileLength + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        log.info("准备下发的CT升级命令是，msg={}", cmd);

        return cmd.getBytes();

    }

    /**
     * 组装升级命令
     *
     * @param opCode     操作码
     * @param httpHost   http下载的ip
     * @param httpPort   http下载的port
     * @param filename   文件名
     * @param MD5        md5
     * @param fileLength 文件长度
     * @return
     */
    public static String assembleFileUpgradeCmdStr(Integer opCode, String httpHost, Integer httpPort, String filename, String MD5, Integer fileLength) {
        // String cmdStr = "{OT,1,47.113.121.87,9992,TP_CT60_ETH_V1.240930.1,CB8210D319D39A1280010802CC6C7B3B,49700,1B36}";
        String beforeCheckStr = CT60_constant.OT + split_comma + opCode + split_comma + httpHost + split_comma + httpPort + split_comma
                + filename + split_comma + MD5 + split_comma + fileLength + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        log.info("准备下发的CT升级命令是，msg={}", cmd);

        return cmd;

    }

    /**
     * 仓位子板信息查询
     *
     * @return
     */
    public static String assembleStockInfoCmdStr() {
        // String cmdStr = "{SQ,111,0,0000}";
        String beforeCheckStr = CT60_constant.SQ + split_comma + getMsgSn() + split_comma + "0" + split_comma;

        String checkCode = computeCRC16(beforeCheckStr + secretKey);

        String cmd = begin + beforeCheckStr + checkCode + end;

        log.info("准备下发的SQ仓位子板信息查询命令是，msg={}", cmd);

        return cmd;

    }


    /**
     * 获取当前报文序列号
     *
     * @return
     */
    public static int getMsgSn() {
        if (msgSn < 65534) {
            msgSn += 1;
        } else {
            msgSn = 0;
        }
        return msgSn;
    }

    /**
     * crc16校验
     *
     * @param input
     * @return
     */
    public static String computeCRC16(String input) {
        CRC32 crc32 = new CRC32();
        crc32.update(input.getBytes());
        long crcValue = crc32.getValue();
        // CRC32值的高16位与低16位进行异或处理，以获取CRC16值
        long crc16 = (crcValue >>> 16) ^ (crcValue & 0xFFFF);
        return Long.toHexString(crc16).toUpperCase();
    }

    public static String getTopicSend(String deviceId) {
        return topic_send_front + deviceId + topic_send_back;
    }


}
